/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
  /* USER CODE END Header */
  /* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#include "usart.h"

#include "chry_ringbuffer.h"
#include "cpost.h"
#include "cevent.h"

/* USER CODE BEGIN 0 */
#define PRINTF_BUFFER_SIZE 64
static char printf_buffer[PRINTF_BUFFER_SIZE];
static volatile int buffer_index = 0;
static uint8_t ch = 0;

#define CHERRY_RINGBUFFER_SIZE 128
static chry_ringbuffer_t rb;
static uint8_t mempool[CHERRY_RINGBUFFER_SIZE];

void flush_printf_buffer (void)
{
    if ( buffer_index > 0 ) {
        HAL_UART_Transmit(&huart1, ( uint8_t* ) printf_buffer, buffer_index, HAL_MAX_DELAY);
        buffer_index = 0;
    }
}
/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init (void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 3000000;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if ( HAL_UART_Init(&huart1) != HAL_OK ) {
        Error_Handler();
    }
    if ( HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK ) {
        Error_Handler();
    }
    if ( HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK ) {
        Error_Handler();
    }
    if ( HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK ) {
        Error_Handler();
    }
    
    HAL_UART_Receive_IT(&huart1, (uint8_t*) &ch, 1);

    chry_ringbuffer_init(&rb, mempool, CHERRY_RINGBUFFER_SIZE);
}

void uart_data_handler (void)
{
    extern void notify_shell_read(void);
    notify_shell_read();
}

uint8_t uart_data_get(uint8_t *data, uint8_t len)
{
    // uint8_t len_s = chry_ringbuffer_read(&rb, data, 1);
    // if (len_s) {
    //     printf(">>> %c <<<\r\n", *data);
    // } else {
    //     printf("<<< no data >>>\r\n");
    // }
    return chry_ringbuffer_read(&rb, data, 1);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1) {
        chry_ringbuffer_write(&rb, &ch, 1);
        cpost(uart_data_handler, 0);
        HAL_UART_Receive_IT(&huart1, (uint8_t*) &ch, 1);
    }
}

void HAL_UART_MspInit (UART_HandleTypeDef* uartHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
    if ( uartHandle->Instance == USART1 ) {
        /* Initializes the peripherals clock */
        PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
        PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
        if ( HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK ) {
            Error_Handler();
        }

        /* USART1 clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();

        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART1 interrupt Init */
        HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    }
}

void HAL_UART_MspDeInit (UART_HandleTypeDef* uartHandle)
{
    if ( uartHandle->Instance == USART1 ) {
        __HAL_RCC_USART1_CLK_DISABLE ();

        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);
    }
}

// 重写fputc带缓冲
int fputc (int ch, FILE* f)
{
    printf_buffer[buffer_index++] = ch;

    // 缓冲区满、换行符时刷新
    if ( buffer_index >= PRINTF_BUFFER_SIZE || ch == '\n' ) {
        flush_printf_buffer();
    }

    return ch;
}

// 提供手动刷新接口
void printf_flush (void)
{
    flush_printf_buffer();
}
/* USER CODE END 1 */
